Skip to content

feat: skip the Swift Testing tests a skip list names - #38

Merged
esnunes merged 2 commits into
mainfrom
feat/swift-testing-skip
Nov 9, 2026
Merged

esnunes merged 2 commits into
mainfrom
feat/swift-testing-skip

Conversation

@esnunes

@esnunes esnunes commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

What

The .coverageAttribution trait now skips the Swift Testing tests that TEST_COVERAGE_ATTRIBUTION_SKIP_FILE names. For a listed test, it calls Test.cancel before the test starts. Swift Testing reports the test as skipped: Xcode and the .xcresult show Skipped, and swift test says it was cancelled.

  • Observer: test_coverage_attribution_is_skipped(module, suite, name) checks the skip list the constructor already loads. It matches names the way XCTest tests are matched, so the format is unchanged. A line names a Swift Testing test the way its records do: the Swift module, the innermost suite, then the display name or the function (ExampleTests/MultiplicationTests/multiply()).
  • Trait: the check runs once per test case, in the outermost trait only, before the scope opens. A cancelled test leaves no record. Cancelling also skips every argument of a parameterized test, and works whether tests run in parallel or not.
  • Swift < 6.3: Test.cancel arrived in Swift 6.3 (Xcode 26.4). Before that, a trait can skip a test only by not running it, and Swift Testing then reports the test as passed. So under #if compiler(>=6.3) the trait cancels, and on older compilers listed tests run as before.
  • Docs: the README now documents the trait, both for evidence and for skipping. It also states the Xcode 26.4 requirement and that a display name containing / can't be listed. @_documentation(visibility: private) is removed now that the README names the trait. AGENTS.md is updated to match.

Why

Skipping covered XCTest only. The README said "a trait has no public way to skip a test", which stopped being true with Swift 6.3's Test.cancel; DataDog's dd-sdk-swift-testing uses it for Test Impact Analysis.

Alternatives considered

  • Not calling the test body: the test is reported as passed even though it never ran, so the result bundle lies. DataDog falls into this on Swift < 6.3: its cancel compiles to nothing there. Here, older compilers run the tests instead.
  • .enabled(if:) / .disabled: the condition closure isn't told which test it's on, so one suite-level trait can't look tests up in a list.
  • Parsing the list in Swift: that would duplicate load_skip_list() and its name normalization. Asking the observer keeps one parser.

Impact

  • On Swift 6.3 and later: listed Swift Testing tests in suites with the trait no longer run. Suites without the trait, and older compilers, behave as before.
  • For Tuist: no change is needed there. The CLI already turns Swift Testing records that didn't overlap into evidence, and test selection doesn't distinguish frameworks. Until now, a Swift Testing test Tuist listed ran anyway; from now on it's skipped. That needs two things:
    • the project links a release that includes this change and builds with Xcode 26.4 or later;
    • the test has evidence. Swift Testing runs tests in parallel by default, and tests that run at the same time are marked overlapped and get none, so Tuist keeps selecting them. Today only runs with parallelization off produce evidence; feat: attribute parallel Swift Testing tests through their tasks #37 brings it to parallel runs.
  • Module names: the trait names a test by its Swift module, while Tuist names it by its test bundle. They match unless a target's product name differs from its module name; in that case the lines don't match and the tests run.
  • Conflicts with feat: attribute parallel Swift Testing tests through their tasks #37: both change the trait, the observer, its header and the README, so whichever merges second needs a rebase.

Validation

  • Xcode 26.6 (Swift 6.3.3):
    • swift test passes all 12 tests.
    • skipsTheListedTests runs serial, parallel and as a shard. In the result bundle, the listed Swift Testing tests show Skipped, the parameterized one included. The unlisted one, and a listed one in a suite without the trait, show Passed. The XCTest expectations are unchanged.
    • skipsTheListedSwiftTestingTests: under SwiftPM, a test listed by its display name leaves no record, and the other test does.
  • Xcode 26.3 (Swift 6.2.4): swift test --filter skipsTheListed passes, with the listed tests run and reported as Passed.
  • mise run test-skip-list, which CI runs on Xcode 26.0.1 and 27.0, now runs both skip tests: the full suite runs only on Xcode 26.3, so without it the Swift 6.3 path under SwiftPM wouldn't run in CI.
  • mise run lint is clean.

🤖 Generated with Claude Code

esnunes and others added 2 commits November 9, 2026 15:44
The `.coverageAttribution` trait asks the observer whether the skip list
names the running test and, when it does, cancels it with `Test.cancel`
before it starts, which reports it as skipped. `Test.cancel` arrived in
Swift 6.3, so older compilers run the listed tests: a test a trait doesn't
run is reported as passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`mise run test-skip-list`, which CI runs on the oldest and newest Xcode,
filtered on `skipsTheListedTests`, which doesn't match
`skipsTheListedSwiftTestingTests`. The full suite runs only on Xcode 26.3
(Swift 6.2), so the Swift 6.3 cancel path under SwiftPM never ran in CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@esnunes
esnunes marked this pull request as ready for review November 9, 2026 19:09
@esnunes
esnunes requested a review from a team as a code owner November 9, 2026 19:09
@esnunes
esnunes requested review from fortmarek and removed request for a team November 9, 2026 19:09
@esnunes
esnunes merged commit 2aeb23c into main Nov 9, 2026
11 checks passed
@esnunes
esnunes deleted the feat/swift-testing-skip branch November 9, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant